home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / transpor / ifmail23.z / ifmail23 / ifmail / ifcico / xmsend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-10  |  9.8 KB  |  502 lines

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <time.h>
  8. #include "session.h"
  9. #include "lutil.h"
  10. #include "ttyio.h"
  11. #include "statetbl.h"
  12.  
  13. #define XMBLKSIZ 128
  14. #define DEFAULT_WINDOW 127
  15.  
  16. extern char* version;
  17.  
  18. extern unsigned short crc16(char*,int);
  19. extern unsigned char checksum(char*,int);
  20. extern long atol(char*);
  21. extern time_t mtime2sl(time_t);
  22. extern int m7send(char*);
  23.  
  24. static char *ln,*rn;
  25. static int flg;
  26.  
  27. static int xm_send(void);
  28.  
  29. int xmsend(char*,char*,int);
  30. int xmsend(local,remote,fl)
  31. char *local,*remote;
  32. int fl;
  33. {
  34.     int rc;
  35.  
  36.     ln=local;
  37.     rn=remote;
  38.     flg=fl;
  39.     rc=xm_send();
  40.     TTYWAIT(1);
  41.     if (rc) loginf("send failed");
  42.     return rc;
  43. }
  44.  
  45. SM_DECL(xm_send,"xmsend")
  46. SM_STATES
  47.     sendm7,sendblk0,waitack0,sendblk,writeblk,
  48.     waitack,resync,sendeot
  49. SM_NAMES
  50.     "sendm7","sendblk0","waitack0","sendblk","writeblk",
  51.     "waitack","resync","sendeot"
  52. SM_EDECL
  53.  
  54.     FILE *fp;
  55.     struct stat st;
  56.     struct flock fl = {
  57.         F_RDLCK,
  58.         0,
  59.         0L,
  60.         0L,
  61.         0
  62.     };
  63.     unsigned short lcrc=0,rcrc;
  64.     int startstate;
  65.     int crcmode,seamode,telink;
  66.     int a,a1,a2;
  67.     int i;
  68.     time_t seatime;
  69.     time_t stm,etm;
  70.  
  71.     unsigned char header=SOH;
  72.     struct _xmblk {
  73.         unsigned char n1;
  74.         unsigned char n2;
  75.         char data[XMBLKSIZ];
  76.         unsigned char c1;
  77.         unsigned char c2;
  78.     } xmblk;
  79.     int count=0;
  80.     int cancount=0;
  81.     int window;
  82.     long last_blk;
  83.     long send_blk;
  84.     long next_blk;
  85.     long ackd_blk;
  86.     long tmp;
  87.  
  88.     char resynbuf[16];
  89.  
  90.     (void)time(&stm);
  91.  
  92.     /* if we got 'C' than hopefully remote is sealink capable... */
  93.  
  94.     if (session_flags & FTSC_XMODEM_CRC)
  95.     {
  96.         telink=0;
  97.         crcmode=1;
  98.         session_flags |= FTSC_XMODEM_RES;
  99.         session_flags |= FTSC_XMODEM_SLO;
  100.         session_flags |= FTSC_XMODEM_XOF;
  101.         window=DEFAULT_WINDOW;
  102.         send_blk=0L;
  103.         next_blk=0L;
  104.         ackd_blk=-1L;
  105.         startstate=sendblk0;
  106.     }
  107.     else 
  108.     {
  109.         telink=1;
  110.         crcmode=0;
  111.         session_flags &= ~FTSC_XMODEM_RES;
  112.         session_flags |= FTSC_XMODEM_SLO;
  113.         session_flags |= FTSC_XMODEM_XOF;
  114.         window=1;
  115.         send_blk=0L;
  116.         next_blk=0L;
  117.         ackd_blk=-1L;
  118.         if (flg && !(session_flags & SESSION_IFNA))
  119.             startstate=sendm7;
  120.         else startstate=sendblk0;
  121.     }
  122.  
  123.     seamode=-1; /* not yet sure about numbered ACKs */
  124.  
  125.     if (stat(ln,&st) != 0)
  126.     {
  127.         logerr("$cannot stat local file \"%s\" to send",ln);
  128.         return 1;
  129.     }
  130.     last_blk=(st.st_size-1)/XMBLKSIZ+1;
  131.  
  132.     if ((fp=fopen(ln,"r")) == NULL)
  133.     {
  134.         logerr("$cannot open local file \"%s\" to send",ln);
  135.         return 1;
  136.     }
  137.     fl.l_pid=getpid();
  138.     if (fcntl(fileno(fp),F_SETLK,&fl) != 0)
  139.     {
  140.         loginf("$cannot lock local file \"%s\" to send, skip it",ln);
  141.         return 0;
  142.     }
  143.     if (stat(ln,&st) != 0)
  144.     {
  145.         loginf("$cannot access local file \"%s\" to send, skip it",ln);
  146.         return 0;
  147.     }
  148.  
  149.     loginf("xmodem send \"%s\" as \"%s\", size=%lu",
  150.         ln,rn,st.st_size);
  151.  
  152. SM_START(startstate)
  153.  
  154. SM_STATE(sendm7)
  155.  
  156.     if (m7send(rn)) {SM_PROCEED(sendblk0);}
  157.     else {SM_ERROR;}
  158.  
  159. SM_STATE(sendblk0)
  160.  
  161.     debug(11,"xmsendblk0 send:%ld, next:%ld, ackd:%ld, last:%ld",
  162.         send_blk,next_blk,ackd_blk,last_blk);
  163.  
  164.     memset(xmblk.data,0,sizeof(xmblk.data));
  165.  
  166.     xmblk.data[0]=(st.st_size)&0xff;
  167.     xmblk.data[1]=(st.st_size>>8)&0xff;
  168.     xmblk.data[2]=(st.st_size>>16)&0xff;
  169.     xmblk.data[3]=(st.st_size>>24)&0xff;
  170.     seatime=mtime2sl(st.st_mtime);
  171.     xmblk.data[4]=(seatime)&0xff;
  172.     xmblk.data[5]=(seatime>>8)&0xff;
  173.     xmblk.data[6]=(seatime>>16)&0xff;
  174.     xmblk.data[7]=(seatime>>24)&0xff;
  175.     strncpy(xmblk.data+8,rn,17);
  176.     if (telink) 
  177.         for (i=23;(i>8) && (xmblk.data[i] == '\0');i--)
  178.             xmblk.data[i]=' ';
  179.     sprintf(xmblk.data+25,"ifcico %s",version);
  180.     xmblk.data[40]=((session_flags & FTSC_XMODEM_SLO) != 0);
  181.     xmblk.data[41]=((session_flags & FTSC_XMODEM_RES) != 0);
  182.     xmblk.data[42]=((session_flags & FTSC_XMODEM_XOF) != 0);
  183.  
  184.     debug(11,"sealink block: \"%s\"",printable(xmblk.data,44));
  185.  
  186.     next_blk=send_blk+1;
  187.     SM_PROCEED(sendblk);
  188.  
  189. SM_STATE(sendblk)
  190.  
  191.     if (send_blk == 0) {SM_PROCEED(writeblk);}
  192.  
  193.     debug(11,"xmsendblk send:%ld, next:%ld, ackd:%ld, last:%ld",
  194.         send_blk,next_blk,ackd_blk,last_blk);
  195.  
  196.     if (send_blk > last_blk)
  197.     {
  198.         if (send_blk == (last_blk+1)) {SM_PROCEED(sendeot);}
  199.         else if (ackd_blk < last_blk) {SM_PROCEED(waitack);}
  200.         else
  201.         {
  202.             (void)time(&etm);
  203.             if (etm == stm) etm++;
  204.             loginf("sent %lu bytes in %lu seconds (%lu cps)",
  205.                 st.st_size,etm-stm,st.st_size/(etm-stm));
  206.             fclose(fp);
  207.             SM_SUCCESS;
  208.         }
  209.     }
  210.  
  211.     memset(xmblk.data,SUB,sizeof(xmblk.data));
  212.  
  213.     if (send_blk != next_blk)
  214.     if (fseek(fp,(send_blk-1)*XMBLKSIZ,SEEK_SET) != 0)
  215.     {
  216.         logerr("$fseek error setting block %ld (byte %lu) in file \"%s\"",
  217.             send_blk,(send_blk-1)*XMBLKSIZ,ln);
  218.         SM_ERROR;
  219.     }
  220.     if (fread(xmblk.data,1,XMBLKSIZ,fp) <= 0)
  221.     {
  222.         logerr("$read error for block %lu in file \"%s\"",
  223.             send_blk,ln);
  224.         SM_ERROR;
  225.     }
  226.     next_blk=send_blk+1;
  227.  
  228.     SM_PROCEED(writeblk);
  229.  
  230. SM_STATE(writeblk)
  231.  
  232.     xmblk.n1=send_blk&0xff;
  233.     xmblk.n2=~xmblk.n1;
  234.     if (crcmode)
  235.     {
  236.         lcrc=crc16(xmblk.data,sizeof(xmblk.data));
  237.         xmblk.c1=(lcrc>>8)&0xff;
  238.         xmblk.c2=lcrc&0xff;
  239.     }
  240.     else
  241.     {
  242.         xmblk.c1=checksum(xmblk.data,sizeof(xmblk.data));
  243.     }
  244.     
  245.     PUTCHAR(header);
  246.     PUT((char*)&xmblk,crcmode?sizeof(xmblk):sizeof(xmblk)-1);
  247.     if (STATUS) {SM_ERROR;}
  248.     if (crcmode)
  249.         debug(11,"sent '\\%03o',no 0x%02x %d bytes crc 0x%04x",
  250.             header,xmblk.n1,XMBLKSIZ,lcrc);
  251.     else
  252.         debug(11,"sent '\\%03o',no 0x%02x, %d bytes checksum 0x%02x",
  253.             header,xmblk.n1,XMBLKSIZ,xmblk.c1);
  254.     send_blk++;
  255.     SM_PROCEED(waitack);
  256.  
  257. SM_STATE(waitack)
  258.  
  259.     if ((count > 4) && (ackd_blk < 0))
  260.     {
  261.         loginf("cannot send sealink block, try xmodem");
  262.         window=1;
  263.         ackd_blk++;
  264.         SM_PROCEED(sendblk);
  265.     }
  266.     if (count > 9)
  267.     {
  268.         loginf("too many errors in xmodem send");
  269.         SM_ERROR;
  270.     }
  271.  
  272.     if ((ackd_blk < 0) || 
  273.         (send_blk > (last_blk+1)) ||
  274.         ((send_blk-ackd_blk) > window))
  275.         TTYWAIT(1);
  276.     else TTYWAIT(0);
  277.  
  278.     a=GETCHAR(20);
  279.     if (a == EMPTY) {SM_PROCEED(sendblk);}
  280.  
  281.     TTYWAIT(1);
  282.     if (a == TIMEOUT)
  283.     {
  284.         if(count++ > 9)
  285.         {
  286.             loginf("too many tries to send block");
  287.             SM_ERROR;
  288.         }
  289.         debug(11,"timeout waiting for ACK");
  290.         send_blk=ackd_blk+1;
  291.         SM_PROCEED(sendblk);
  292.     }
  293.     else if (a < 0)
  294.     {
  295.         SM_ERROR;
  296.     }
  297.     else switch (a)
  298.     {
  299.     case ACK:
  300.         count=0;
  301.         cancount=0;
  302.         switch (seamode)
  303.         {
  304.         case -1: if ((a1=GETCHAR(1)) < 0)
  305.             {
  306.                 seamode=0;
  307.                 UNGETCHAR(a);
  308.                 SM_PROCEED(waitack);
  309.             }
  310.             else if ((a2=GETCHAR(1)) < 0)
  311.             {
  312.                 seamode=0;
  313.                 UNGETCHAR(a1);
  314.                 UNGETCHAR(a);
  315.                 SM_PROCEED(waitack);
  316.             }
  317.             else if ((a1&0xff) != ((~a2)&0xff))
  318.             {
  319.                 seamode=0;
  320.                 UNGETCHAR(a2);
  321.                 UNGETCHAR(a1);
  322.                 UNGETCHAR(a);
  323.                 SM_PROCEED(waitack);
  324.             }
  325.             else
  326.             {
  327.                 seamode=1;
  328.                 UNGETCHAR(a2);
  329.                 UNGETCHAR(a1);
  330.                 UNGETCHAR(a);
  331.                 SM_PROCEED(waitack);
  332.             }
  333.             break;
  334.         case 0:
  335.             ackd_blk++;
  336.             SM_PROCEED(sendblk);
  337.             break;
  338.         case 1:
  339.             a1=GETCHAR(1);
  340.             a2=GETCHAR(1);
  341.             if ((a1 < 0) || (a2 < 0) || (a1 != ((~a2)&0xff)))
  342.             {
  343.                 debug(11,"bad ACK: 0x%02x/0x%02x, ignore",
  344.                     a1,a2);
  345.                 SM_PROCEED(sendblk);
  346.             }
  347.             else
  348.             {
  349.                 if (a1 != ((ackd_blk+1)&0xff))
  350.                     debug(11,"got ACK %d, expected %d",
  351.                         a1,(ackd_blk+1)&0xff);
  352.                 tmp=send_blk-((send_blk-a1)&0xff);
  353.                 if ((tmp > ackd_blk) && (tmp < send_blk))
  354.                     ackd_blk=tmp;
  355.                 else
  356.                     debug(11,"bad ACK: %ld, ignore",
  357.                         a1,a2);
  358.                 if ((ackd_blk+1) == send_blk)
  359.                     {SM_PROCEED(sendblk);}
  360.                 else /* read them all if more than 1 */
  361.                     {SM_PROCEED(waitack);}
  362.             }
  363.             break;
  364.         }
  365.         break;
  366.     case NAK:    if (ackd_blk <= 0) crcmode=0;
  367.             count++;
  368.             send_blk=ackd_blk+1;
  369.             SM_PROCEED(sendblk);
  370.             break;
  371.     case SYN:    SM_PROCEED(resync);
  372.             break;
  373.     case DC3:    if (session_flags & FTSC_XMODEM_XOF)
  374.             while (((a=GETCHAR(15)) > 0) && (a != DC1))
  375.                 if (a < 0) debug(11,"got %d waiting for DC1",a);
  376.                 else debug(11,"got '%s' waiting for DC1",
  377.                     printablec(a));
  378.             SM_PROCEED(waitack);
  379.             break;
  380.     case CAN:    if (cancount++ > 5)
  381.             {
  382.                 loginf("remote requested cancel transfer");
  383.                 SM_ERROR;
  384.             }
  385.             else {SM_PROCEED(waitack);}
  386.             break;
  387.     case 'C':    if (ackd_blk < 0)
  388.             {
  389.                 crcmode=1;
  390.                 count++;
  391.                 send_blk=ackd_blk+1;
  392.                 SM_PROCEED(sendblk);
  393.             }
  394.             /* fallthru */
  395.     default:    if (a < ' ') debug(11,"got '\\%03o' waiting for ACK",a);
  396.             else debug(11,"got '%c' waiting for ACK",a);
  397.             SM_PROCEED(waitack);
  398.             break;
  399.     }
  400.  
  401. SM_STATE(resync)
  402.  
  403.     if (count++ > 9)
  404.     {
  405.         loginf("too may tries to resync");
  406.         SM_ERROR;
  407.     }
  408.  
  409.     i=-1;
  410.     do
  411.     {
  412.         a=GETCHAR(15);
  413.         resynbuf[++i]=a;
  414.     }
  415.     while ((a >= '0') && (a <= '9') && (i < sizeof(resynbuf)-1));
  416.     resynbuf[i]='\0';
  417.     debug(11,"got resync \"%s\", i=%d",resynbuf,i);
  418.     lcrc=crc16(resynbuf,strlen(resynbuf));
  419.     rcrc=0;
  420.     if (a != ETX)
  421.     {
  422.         if (a > 0) loginf("got %d waiting for resync",a);
  423.         else loginf("got %s waiting for resync",printablec(a));
  424.         PUTCHAR(NAK);
  425.         SM_PROCEED(waitack);
  426.     }
  427.     if ((a=GETCHAR(1)) < 0)
  428.     {
  429.         PUTCHAR(NAK);
  430.         SM_PROCEED(waitack);
  431.     }
  432.     rcrc=a&0xff;
  433.     if ((a=GETCHAR(1)) < 0)
  434.     {
  435.         PUTCHAR(NAK);
  436.         SM_PROCEED(waitack);
  437.     }
  438.     rcrc |= (a << 8);
  439.     if (rcrc != lcrc)
  440.     {
  441.         loginf("bad resync crc: 0x%04x != 0x%04x",lcrc,rcrc);
  442.         PUTCHAR(NAK);
  443.         SM_PROCEED(waitack);
  444.     }
  445.     send_blk=atol(resynbuf);
  446.     ackd_blk=send_blk-1;
  447.     loginf("resyncing at block %ld (byte %lu)",
  448.         send_blk,(send_blk-1L)*XMBLKSIZ);
  449.     PUTCHAR(ACK);
  450.     SM_PROCEED(sendblk);
  451.  
  452. SM_STATE(sendeot)
  453.  
  454.     PUTCHAR(EOT);
  455.     if (STATUS) {SM_ERROR;}
  456.     send_blk++;
  457.     SM_PROCEED(waitack);
  458.  
  459. SM_END
  460. SM_RETURN
  461.  
  462.  
  463. int xmsndfiles(file_list*);
  464. int xmsndfiles(tosend)
  465. file_list *tosend;
  466. {
  467.     int rc,c,gotnak,count;
  468.     file_list *nextsend;
  469.  
  470.     for (nextsend=tosend;nextsend;nextsend=nextsend->next)
  471.     if (*(nextsend->local) != '~')
  472.     {    
  473.         if (nextsend->remote)
  474.         if ((rc=xmsend(nextsend->local,nextsend->remote,
  475.                 (nextsend != tosend)))) /* send m7 for rest */
  476.             return rc; /* and thus avoid execute_disposition() */
  477.         else 
  478.         {
  479.             gotnak=0;
  480.             count=0;
  481.             while (!gotnak && (count < 6))
  482.             {
  483.                 c=GETCHAR(15);
  484.                 if (c < 0) return STATUS;
  485.                 if (c == CAN)
  486.                 {
  487.                     loginf("remote refused receiving");
  488.                     return 1;
  489.                 }
  490.                 if ((c == 'C') || (c == NAK)) gotnak=1;
  491.                 else debug(11,"got '%s' waiting NAK",
  492.                     printablec(c));
  493.             }
  494.             if (c == 'C') session_flags |= FTSC_XMODEM_CRC;
  495.             if (!gotnak) return 1;
  496.         }
  497.         execute_disposition(nextsend);
  498.     }
  499.     PUTCHAR(EOT);
  500.     return STATUS;
  501. }
  502.